/*
 * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package java.nio.channels;

import java.io.IOException;
import java.net.ProtocolFamily;
import java.net.DatagramSocket;
import java.net.SocketOption;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.spi.AbstractSelectableChannel;
import java.nio.channels.spi.SelectorProvider;

/**
 * 面向数据报的套接字的可选择通道。
 *
 * <p> 通过调用该类的open方法之一创建数据报通道。
 * 不能为任意预先存在的数据报套接字创建通道。新创建的数据报通道打开但未连接。
 * 为了使用发送和接收方法，不需要连接数据报通道。
 * 一个数据报通道可以通过调用它的connect方法被连接，以避免安全检查的开销，否则作为每个发送和接收操作的一部分执行。
 * 为了使用读和写方法，数据报通道必须连接起来，因为这些方法不接受或返回套接字地址。
 *
 * <p> 一旦连接，数据报通道将保持连接，直到断开或关闭。
 * 数据报通道是否连接，可以通过调用它的isConnected方法来确定。
 *
 * <p> 套接字选项使用setOption方法进行配置。到Internet协议套接字的数据报通道支持以下选项:
 * <blockquote>
 * <table border summary="Socket options">
 *   <tr>
 *     <th>Option Name</th>
 *     <th>Description</th>
 *   </tr>
 *   <tr>
 *     <td> {@link java.net.StandardSocketOptions#SO_SNDBUF SO_SNDBUF} </td>
 *     <td> 发送缓冲区的大小</td>
 *   </tr>
 *   <tr>
 *     <td> {@link java.net.StandardSocketOptions#SO_RCVBUF SO_RCVBUF} </td>
 *     <td> 接收缓冲区的大小</td>
 *   </tr>
 *   <tr>
 *     <td> {@link java.net.StandardSocketOptions#SO_REUSEADDR SO_REUSEADDR} </td>
 *     <td> 重用地址 </td>
 *   </tr>
 *   <tr>
 *     <td> {@link java.net.StandardSocketOptions#SO_BROADCAST SO_BROADCAST} </td>
 *     <td> 允许广播数据报的传输 </td>
 *   </tr>
 *   <tr>
 *     <td> {@link java.net.StandardSocketOptions#IP_TOS IP_TOS} </td>
 *     <td> 报头中的服务类型(ToS)字节</td>
 *   </tr>
 *   <tr>
 *     <td> {@link java.net.StandardSocketOptions#IP_MULTICAST_IF IP_MULTICAST_IF} </td>
 *     <td> 因特网协议(IP)多播数据报的网络接口</td>
 *   </tr>
 *   <tr>
 *     <td> {@link java.net.StandardSocketOptions#IP_MULTICAST_TTL
 *       IP_MULTICAST_TTL} </td>
 *     <td> 多播数据报的存活时间 </td>
 *   </tr>
 *   <tr>
 *     <td> {@link java.net.StandardSocketOptions#IP_MULTICAST_LOOP
 *       IP_MULTICAST_LOOP} </td>
 *     <td> (IP)组播数据报 </td>
 *   </tr>
 * </table>
 * </blockquote>
 * 还可能支持其他(特定于实现的)选项。
 * 
 * <p> 数据报通道对于多个并发线程来说是安全的。它们支持并发读写，尽管在任何给定的时间内最多有一个线程在读，最多有一个线程在写。 </p>
 *
 * @author Mark Reinhold
 * @author JSR-51 Expert Group
 * @since 1.4
 */

public abstract class DatagramChannel
    extends AbstractSelectableChannel
    implements ByteChannel, ScatteringByteChannel, GatheringByteChannel, MulticastChannel
{

    /**
     * 创建实例
     *
     * @param  provider
     *         The provider that created this channel
     */
    protected DatagramChannel(SelectorProvider provider) {
        super(provider);
    }

    /**
     * 打开数据报通道。
     *
     * <p> 新通道是通过调用系统范围默认java.nio.channels.spi.SelectorProvider
     * 对象的openDatagramChannel方法创建的。通道无法连接。
     *
     * <p> 通道的套接字的协议族依赖于平台(可能还有配置)，因此未指定。
     * 开放允许在打开一个数据报通道时选择协议族，并且应该用于开放用于Internet协议组播的数据报通道。
     *
     * @return  A new datagram channel
     *
     * @throws  IOException
     *          If an I/O error occurs
     */
    public static DatagramChannel open() throws IOException {
        return SelectorProvider.provider().openDatagramChannel();
    }

    /**
     * 打开数据报通道。
     *
     * <p> family参数用于指定协议族。
     * 如果数据报通道被用于IP多播，那么它应该对应于该通道将要加入的多播组的地址类型。
     *
     * <p> 新通道是通过调用系统范围默认java.nio.channels.spi.SelectorProvider对象的openDatagramChannel方法创建的。通道无法连接。
     *
     * @param   family
     *          The protocol family
     *
     * @return  A new datagram channel
     *
     * @throws  UnsupportedOperationException
     *          If the specified protocol family is not supported. For example,
     *          suppose the parameter is specified as {@link
     *          java.net.StandardProtocolFamily#INET6 StandardProtocolFamily.INET6}
     *          but IPv6 is not enabled on the platform.
     * @throws  IOException
     *          If an I/O error occurs
     *
     * @since   1.7
     */
    public static DatagramChannel open(ProtocolFamily family) throws IOException {
        return SelectorProvider.provider().openDatagramChannel(family);
    }

    /**
     * 返回一个操作集，标识此通道支持的操作。
     *
     * <p> 数据报通道支持读写，因此该方法返回(SelectionKey.OP_READ | SelectionKey.OP_WRITE)。</p>
     *
     * @return  The valid-operation set
     */
    public final int validOps() {
        return (SelectionKey.OP_READ
                | SelectionKey.OP_WRITE);
    }


    // -- Socket-specific operations --

    /**
     * @throws  AlreadyBoundException               {@inheritDoc}
     * @throws  UnsupportedAddressTypeException     {@inheritDoc}
     * @throws  ClosedChannelException              {@inheritDoc}
     * @throws  IOException                         {@inheritDoc}
     * @throws  SecurityException
     *          If a security manager has be en installed and its {@link
     *          SecurityManager#checkListen checkListen} method denies the
     *          operation
     *
     * @since 1.7
     */
    public abstract DatagramChannel bind(SocketAddress local)
        throws IOException;

    /**
     * @throws  UnsupportedOperationException           {@inheritDoc}
     * @throws  IllegalArgumentException                {@inheritDoc}
     * @throws  ClosedChannelException                  {@inheritDoc}
     * @throws  IOException                             {@inheritDoc}
     *
     * @since 1.7
     */
    public abstract <T> DatagramChannel setOption(SocketOption<T> name, T value)
        throws IOException;

    /**
     * 检索与此通道相关联的数据报套接字。
     *
     * <p> 返回的对象不会声明没有在java.net.DatagramSocket类中声明的任何公共方法。  </p>
     *
     * @return  A datagram socket associated with this channel
     */
    public abstract DatagramSocket socket();

    /**
     * 告诉该通道的套接字是否已连接。
     *
     * @return  {@code true} if, and only if, this channel's socket
     *          is {@link #isOpen open} and connected
     */
    public abstract boolean isConnected();

    /**
     * 连接此通道的套接字。
     *
     * <p> 通道的套接字被配置为只从给定的远端对端地址接收数据报，并发送数据报。
     * 一旦连接，数据报可能不能从或发送到任何其他地址。
     * 数据报套接字一直保持连接，直到显式断开连接或关闭为止。
     *
     * <p> 此方法执行的安全检查与java.net.DatagramSocket类的connect方法完全相同。
     * 也就是说，如果已经安装了安全管理器，那么该方法将验证其checkAccept和checkConnect方法
     * 允许数据报分别从给定的远程地址接收和发送。
     *
     * <p> 这个方法可以在任何时候被调用。
     * 它不会对在它被调用时已经在进行的读或写操作产生任何影响。
     * 如果该通道的套接字没有被绑定，那么该方法首先会导致套接字绑定到一个自动分配的地址，就像调用参数为null的bind方法一样。 </p>
     *
     * @param  remote
     *         The remote address to which this channel is to be connected
     *
     * @return  This datagram channel
     *
     * @throws  ClosedChannelException
     *          If this channel is closed
     *
     * @throws  AsynchronousCloseException
     *          If another thread closes this channel
     *          while the connect operation is in progress
     *
     * @throws  ClosedByInterruptException
     *          If another thread interrupts the current thread
     *          while the connect operation is in progress, thereby
     *          closing the channel and setting the current thread's
     *          interrupt status
     *
     * @throws  SecurityException
     *          If a security manager has been installed
     *          and it does not permit access to the given remote address
     *
     * @throws  IOException
     *          If some other I/O error occurs
     */
    public abstract DatagramChannel connect(SocketAddress remote)
        throws IOException;

    /**
     * 断开此通道的套接字。
     *
     * <p> 通道的套接字被配置为，只要安装了securitymanager，它就可以从任何远程地址接收数据报，并将数据报发送到任何远程地址。
     *
     * <p> 这个方法可以在任何时候被调用。它不会对在它被调用时已经在进行的读或写操作产生任何影响。
     *
     * <p> 如果此通道的套接字未连接，或者通道已关闭，则调用此方法没有效果。 </p>
     *
     * @return  This datagram channel
     *
     * @throws  IOException
     *          If some other I/O error occurs
     */
    public abstract DatagramChannel disconnect() throws IOException;

    /**
     * 返回此通道套接字连接到的远程地址。
     *
     * @return  The remote address; {@code null} if the channel's socket is not
     *          connected
     *
     * @throws  ClosedChannelException
     *          If the channel is closed
     * @throws  IOException
     *          If an I/O error occurs
     *
     * @since 1.7
     */
    public abstract SocketAddress getRemoteAddress() throws IOException;

    /**
     * 通过这个通道接收数据报。
     *
     * <p> 如果一个数据报是立即可用的，或者如果这个通道是阻塞模式，
     * 并且一个最终成为可用的，那么这个数据报被复制到给定的字节缓冲区并返回它的源地址。
     * 如果该通道处于非阻塞模式，并且数据报不立即可用，则该方法立即返回null。
     *
     * <p> 数据报被转移到从当前位置开始的给定字节缓冲区，就像通过一个常规的读操作一样。
     * 如果缓冲区中剩余的字节数少于保存数据报所需的字节数，则数据报的剩余部分将被静默丢弃。
     *
     * <p> 此方法执行与java.net.DatagramSocket类的receive方法完全相同的安全检查。
     * 也就是说，如果套接字没有连接到特定的远程地址，并且已经安装了安全管理器，
     * 那么对于接收到的每个数据报，该方法将验证源地址和端口号是否被安全管理器的checkAccept方法允许。
     * 首先通过connect方法连接套接字可以避免这种安全检查的开销。
     *
     * <p> 这个方法可以在任何时候被调用。
     * 但是，如果另一个线程已经在这个通道上发起了一个读操作，那么对这个方法的调用将会阻塞，直到第一个操作完成。
     * 如果该通道的套接字没有被绑定，那么这个方法首先会导致套接字绑定到一个自动分配的地址，就像调用参数为null的bind方法一样。 </p>
     *
     * @param  dst
     *         The buffer into which the datagram is to be transferred
     *
     * @return  The datagram's source address,
     *          or <tt>null</tt> if this channel is in non-blocking mode
     *          and no datagram was immediately available
     *
     * @throws  ClosedChannelException
     *          If this channel is closed
     *
     * @throws  AsynchronousCloseException
     *          If another thread closes this channel
     *          while the read operation is in progress
     *
     * @throws  ClosedByInterruptException
     *          If another thread interrupts the current thread
     *          while the read operation is in progress, thereby
     *          closing the channel and setting the current thread's
     *          interrupt status
     *
     * @throws  SecurityException
     *          If a security manager has been installed
     *          and it does not permit datagrams to be accepted
     *          from the datagram's sender
     *
     * @throws  IOException
     *          If some other I/O error occurs
     */
    public abstract SocketAddress receive(ByteBuffer dst) throws IOException;

    /**
     * 通过这个通道发送数据报。
     *
     * <p> 如果该通道处于非阻塞模式并且底层输出缓冲区中有足够的空间，
     * 或者如果该通道处于阻塞模式并且有足够的空间可用，
     * 那么给定缓冲区中的剩余字节将作为单个数据报传输到给定的目标地址。
     *
     * <p> 数据报从字节缓冲区传送，就像通过常规的写操作一样。
     *
     * <p> 此方法执行与java.net.DatagramSocket类的send方法完全相同的安全检查。
     * 也就是说，如果套接字没有连接到特定的远程地址，并且已经安装了安全管理器，
     * 那么对于发送的每个数据报，该方法将验证安全管理器的checkConnect方法是否允许目标地址和端口号。
     * 这种安全检查的开销可以通过connect方法首先连接套接字来避免。
     *
     * <p> 这个方法可以在任何时候被调用。
     * 但是，如果另一个线程已经在这个通道上发起了写操作，那么对这个方法的调用将会阻塞，直到第一个操作完成。
     * 如果该通道的套接字没有被绑定，那么这个方法首先会导致套接字绑定到一个自动分配的地址，就像通过调用参数为null的bind方法一样。</p>
     *
     * @param  src
     *         The buffer containing the datagram to be sent
     *
     * @param  target
     *         The address to which the datagram is to be sent
     *
     * @return   The number of bytes sent, which will be either the number
     *           of bytes that were remaining in the source buffer when this
     *           method was invoked or, if this channel is non-blocking, may be
     *           zero if there was insufficient room for the datagram in the
     *           underlying output buffer
     *
     * @throws  ClosedChannelException
     *          If this channel is closed
     *
     * @throws  AsynchronousCloseException
     *          If another thread closes this channel
     *          while the read operation is in progress
     *
     * @throws  ClosedByInterruptException
     *          If another thread interrupts the current thread
     *          while the read operation is in progress, thereby
     *          closing the channel and setting the current thread's
     *          interrupt status
     *
     * @throws  SecurityException
     *          If a security manager has been installed
     *          and it does not permit datagrams to be sent
     *          to the given address
     *
     * @throws  IOException
     *          If some other I/O error occurs
     */
    public abstract int send(ByteBuffer src, SocketAddress target)
        throws IOException;


    // -- ByteChannel operations --

    /**
     * 从这个通道读取数据报。
     *
     * <p> 此方法只能在该通道的套接字已连接的情况下被调用，并且只接受来自套接字对等体的数据报。
     * 如果数据报中的字节数多于保留在给定缓冲区中的字节数，则数据报的其余部分将被静默丢弃。
     * 否则，该方法的行为与ReadableByteChannel接口中指定的完全一致。</p>
     *
     * @throws  NotYetConnectedException
     *          If this channel's socket is not connected
     */
    public abstract int read(ByteBuffer dst) throws IOException;

    /**
     * Reads a datagram from this channel.
     *
     * <p> This method may only be invoked if this channel's socket is
     * connected, and it only accepts datagrams from the socket's peer.  If
     * there are more bytes in the datagram than remain in the given buffers
     * then the remainder of the datagram is silently discarded.  Otherwise
     * this method behaves exactly as specified in the {@link
     * ScatteringByteChannel} interface.  </p>
     *
     * @throws  NotYetConnectedException
     *          If this channel's socket is not connected
     */
    public abstract long read(ByteBuffer[] dsts, int offset, int length)
        throws IOException;

    /**
     * Reads a datagram from this channel.
     *
     * <p> This method may only be invoked if this channel's socket is
     * connected, and it only accepts datagrams from the socket's peer.  If
     * there are more bytes in the datagram than remain in the given buffers
     * then the remainder of the datagram is silently discarded.  Otherwise
     * this method behaves exactly as specified in the {@link
     * ScatteringByteChannel} interface.  </p>
     *
     * @throws  NotYetConnectedException
     *          If this channel's socket is not connected
     */
    public final long read(ByteBuffer[] dsts) throws IOException {
        return read(dsts, 0, dsts.length);
    }

    /**
     * Writes a datagram to this channel.
     *
     * <p> This method may only be invoked if this channel's socket is
     * connected, in which case it sends datagrams directly to the socket's
     * peer.  Otherwise it behaves exactly as specified in the {@link
     * WritableByteChannel} interface.  </p>
     *
     * @throws  NotYetConnectedException
     *          If this channel's socket is not connected
     */
    public abstract int write(ByteBuffer src) throws IOException;

    /**
     * Writes a datagram to this channel.
     *
     * <p> This method may only be invoked if this channel's socket is
     * connected, in which case it sends datagrams directly to the socket's
     * peer.  Otherwise it behaves exactly as specified in the {@link
     * GatheringByteChannel} interface.  </p>
     *
     * @return   The number of bytes sent, which will be either the number
     *           of bytes that were remaining in the source buffer when this
     *           method was invoked or, if this channel is non-blocking, may be
     *           zero if there was insufficient room for the datagram in the
     *           underlying output buffer
     *
     * @throws  NotYetConnectedException
     *          If this channel's socket is not connected
     */
    public abstract long write(ByteBuffer[] srcs, int offset, int length)
        throws IOException;

    /**
     * Writes a datagram to this channel.
     *
     * <p> This method may only be invoked if this channel's socket is
     * connected, in which case it sends datagrams directly to the socket's
     * peer.  Otherwise it behaves exactly as specified in the {@link
     * GatheringByteChannel} interface.  </p>
     *
     * @return   The number of bytes sent, which will be either the number
     *           of bytes that were remaining in the source buffer when this
     *           method was invoked or, if this channel is non-blocking, may be
     *           zero if there was insufficient room for the datagram in the
     *           underlying output buffer
     *
     * @throws  NotYetConnectedException
     *          If this channel's socket is not connected
     */
    public final long write(ByteBuffer[] srcs) throws IOException {
        return write(srcs, 0, srcs.length);
    }

    /**
     * {@inheritDoc}
     * <p>
     * 如果设置了安全管理器，则使用本地地址和-1作为参数调用其checkConnect方法，以查看是否允许该操作。
     * 如果不允许该操作，则返回一个表示环回地址和通道套接字的本地端口的SocketAddress。
     *
     * @return  The {@code SocketAddress} that the socket is bound to, or the
     *          {@code SocketAddress} representing the loopback address if
     *          denied by the security manager, or {@code null} if the
     *          channel's socket is not bound
     *
     * @throws  ClosedChannelException     {@inheritDoc}
     * @throws  IOException                {@inheritDoc}
     */
    @Override
    public abstract SocketAddress getLocalAddress() throws IOException;

}
